package service

import (
	"fmt"
	"gitee.com/zhouli1369/go2struct/internal/dto"
	"gitee.com/zhouli1369/go2struct/internal/utils"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

type MysqlStrategy struct {
	// 参数
	Param dto.CmdParam
}

func (s *MysqlStrategy) GetName() string {
	return s.Param.Driver
}

var Dbo *gorm.DB

// QueryDataInfo  查询mysql的数据库、表、列信息
func (s *MysqlStrategy) QueryDataInfo() (dbInfo dto.DbInfo, err error) {
	// Dbo 数据库链接
	s.initDb()
	fmt.Println("[MysqlStrategy]")

	//Dbo.Raw("SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_COMMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA=? ORDER BY TABLE_NAME ASC;", dbname).Scan(&tables)
	Dbo.Table("information_schema.TABLES").Select("TABLE_SCHEMA,TABLE_NAME,TABLE_COMMENT").Where("TABLE_SCHEMA=?", s.Param.DbName).Order("TABLE_NAME ASC").Scan(&dbInfo.DbTables)
	//fmt.Println("================================查表信息======================================")
	//fmt.Println(tables)
	//查所有列信息
	var columns []dto.Columns
	//err = Dbo.Raw("SELECT TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,COLUMN_KEY,ORDINAL_POSITION,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,COLUMN_TYPE,EXTRA,COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME,ORDINAL_POSITION ASC;", dbname).Scan(&columns).Error
	err = Dbo.Table("information_schema.COLUMNS").Select("TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME,COLUMN_KEY,ORDINAL_POSITION,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE,COLUMN_TYPE,EXTRA,COLUMN_COMMENT").Where("TABLE_SCHEMA=?", s.Param.DbName).Order("TABLE_NAME,ORDINAL_POSITION ASC").Scan(&columns).Error
	//fmt.Println("================================查列信息======================================")
	//fmt.Println(columns)
	//循环列信息，映射golang数据类型
	for j := range columns {

		columns[j].GoName = utils.ToUpperCamelCase(columns[j].ColumnName)   //格式化列名
		columns[j].JsonName = utils.ToLowerCamelCase(columns[j].ColumnName) //格式化列名
		columns[j].GoType = utils.MysqlToGoType(columns[j].DataType)        //数据库类型转golang类型
	}
	var k int = 0
	//循环表信息，设置命名空间，并把表的列名都添加进去方便template使用
	for i := range dbInfo.DbTables {
		dbInfo.DbTables[i].PackageName = s.Param.GoNameSpace
		dbInfo.DbTables[i].GoName = utils.ToUpperCamelCase(dbInfo.DbTables[i].TableName) + "PO" //格式化表名
		dbInfo.DbTables[i].Imports = make(map[string]string)                                    //初始化当前表的包
		//这里减少了重复循环，前提是表名、列名里的TABLE_NAME排过序的，否则会有问题
		for ; k < len(columns); k++ {
			if dbInfo.DbTables[i].TableName == columns[k].TableName {
				//把列名添加到表的数据结构里
				dbInfo.DbTables[i].TableColumns = append(dbInfo.DbTables[i].TableColumns, columns[k])
				//====下面是添加包的逻辑
				if _, ok := dbInfo.DbTables[i].Imports["time"]; !ok && columns[k].GoType == "time.Time" {
					//判断表中的Packages是否已经存在time，不存在就添加time包
					dbInfo.DbTables[i].Imports["time"] = "time"
				}
			} else {
				break
			}
		}
	}
	return
}

func (s *MysqlStrategy) initDb() {
	var gormConfig gorm.Config
	gormConfig.Logger = logger.Default.LogMode(logger.Info)
	var err error
	Dbo, err = gorm.Open(mysql.Open(s.Param.Dsn), &gormConfig)
	if err != nil {
		panic(err)
	} else {
		sqlDB, err := Dbo.DB()
		if err == nil && sqlDB != nil {
			sqlDB.SetMaxIdleConns(10)
			//设置最大的数据库连接数，默认值=0（没有限制）
			//Dbo.DB().SetMaxOpenConns(10)
			sqlDB.SetMaxOpenConns(20)
			//设置连接可复用的最大时间
			sqlDB.SetConnMaxLifetime(-1)
			//ping数据库
			//err = Dbo.DB().Ping()
			err = sqlDB.Ping()
			if err != nil {
				panic(err)
			} else {
				fmt.Println(fmt.Sprintf("%s database is connected.", s.Param.Driver))
			}
		}
	}
}
